package com.hqbzl.c1.check;

import lombok.Getter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.LongAdder;
import java.util.function.Predicate;
import java.util.stream.Collectors;

@Slf4j
public class TestFileWalk {


    static class ScanFilter extends Thread {
        private Path path;
        protected final Predicate<Path> pathPredicate;
        @Getter
        protected LongAdder longAdder = new LongAdder();
        @Getter
        private List<Path> files = new ArrayList<>();
        private CountDownLatch countDownLatch;

        public ScanFilter(Path path, Predicate<Path> pathPredicate, CountDownLatch countDownLatch) {
            this.path = path;
            this.pathPredicate = pathPredicate;
            this.countDownLatch = countDownLatch;
        }

        @SneakyThrows
        @Override
        public void run() {
            try {
                Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
                    @Override
                    public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                        final String filePath = file.toAbsolutePath().toString();
//                        System.out.println("filePath = " + filePath);
                        if (pathPredicate.test(file)) {
                            longAdder.increment();
                            files.add(file);
                            //System.out.println("filePath = " + file.toAbsolutePath().toString());
                            //System.out.println("path.getFileName().toString() = " + path.getFileName().toString());
//                            System.out.println("path.getFileName().toString() = " + file.getFileName().toString());
                            return FileVisitResult.CONTINUE;
                        }
                    /*
                    if (filePath.endsWith(".mp4")) {
                    }
                     */
                        return super.visitFile(file, attrs);
//                        return FileVisitResult.CONTINUE;
                    }
                });
            } finally {
                countDownLatch.countDown();
            }
        }
    }

    static class AllScan {
        private Predicate<Path> pathPredicate;
        private CountDownLatch countDownLatch;
        private List<Path> paths;
        //final List<ScanFilter> scanFilters = new ArrayList<>();
        @Getter
        List<Path> list = new ArrayList<>();
        @Getter
        final AtomicInteger total = new AtomicInteger(0);

        @Getter
        final HashMap<Long, ArrayList<String>> kvalus = new HashMap<>();

        public AllScan(Predicate<Path> pathPredicate, List<Path> paths) {
            this.pathPredicate = pathPredicate;
            this.paths = paths;
            countDownLatch = new CountDownLatch(paths.size());
        }

        public void start() {
            final List<ScanFilter> scanFilters = paths.stream().map(x -> new ScanFilter(x, pathPredicate, countDownLatch)).collect(Collectors.toList());
            scanFilters.forEach(x -> {
                x.start();
            });
            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            scanFilters.forEach(x -> {
                list.addAll(x.getFiles());
                total.updateAndGet(y -> y + x.getLongAdder().intValue());
            });
        }
    }


    public static HashMap<String, ArrayList<Path>> summary(final List<Path> list) {
        final HashMap<String, ArrayList<Path>> kvalus = new HashMap<>();
        final HashMap<Long, ArrayList<String>> useSizeGroup = new HashMap<>();
        final ArrayList<Path> allFiles = new ArrayList<>();
        list.forEach(path -> {
//            final long usableSpace = path.toFile().getUsableSpace();
//            path.toFile().length();
            String fileName = path.getFileName().toString();
            try {
                final long size = Files.size(path);
                useSizeGroup.computeIfAbsent(size, k -> new ArrayList<>()).add(fileName);
            } catch (IOException e) {
                e.printStackTrace();
            }
            final String[] split = fileName.trim().split(" ");
            if (split.length > 1) {
                final String key = split[0].toUpperCase();
                kvalus.computeIfAbsent(key, k -> new ArrayList<>()).add(path);
            }
        });
        useSizeGroup.forEach((k, v) -> {
            if (v.size() > 1) {
                System.out.println("v.size() = " + k);
                v.stream().forEach(x -> System.out.println("\t" + x));
            }
        });
        return kvalus;
    }

    public static void copyFile(final AllScan allScan, String targetDirectories) throws IOException {
        System.out.println("=============================================================== 复制文件");
        final List<Path> ff = allScan.getList();
        for (int i = 0; i < ff.size(); i++) {
            final Path path = ff.get(i);
            final Path target = Paths.get("E:\\video\\" + targetDirectories + "\\" + path.getFileName());
            Path parentPath = target.toFile().getParentFile().toPath();
            final boolean exists = Files.exists(parentPath);
            if (i == 0 && !exists) {
                System.out.println("目标不存在，创建 " + parentPath.toFile().getAbsolutePath());
                Files.createDirectories(parentPath);
            }
            final boolean targetExists = Files.exists(target);
            if (targetExists) {
                System.out.println("目标文件　" + target.toFile().getAbsolutePath() + " 已存在，跳过");
                continue;
            }
            System.out.println("\t复制第" + (i + 1) + "/" + ff.size() + "个文件 开始");
            Files.copy(path, target);
            System.out.println("\t复制第" + (i + 1) + "/" + ff.size() + "个文件 完成");
            Files.delete(path);
            System.out.println("删除原文件 " + path.toFile().getAbsolutePath() + " 完成");
        }
        System.out.println("复制 " + targetDirectories + " 完成");
    }

    public static void copyFiles() throws IOException {
        final List<String> names = Arrays.asList("東條なつ", "明里つむぎ", "新ありな", "篠田ゆう", "天馬ゆい", "星乃莉子", "吉根ゆりあ", "新村あかり", "JULIA", "希島あいり", "木下ひまり（花沢ひ", "神宮寺ナオ", "架乃ゆら", "花狩まい", "沙月恵奈", "鷲尾めい", "八木奈々", "新井リマ", "山岸逢花", "本郷愛（二階堂夢）", "葵つかさ", "神木麗", "天川そら", "恋渕ももな", "奥田咲", "小宵こなん", "木下凛々子", "夢乃あいか", "梓ヒカリ", "愛弓りょう", "天使もえ", "MINAMO", "本庄鈴", "美谷朱里", "加美杏奈", "美乃すずめ", "宮島めい", "桃乃木かな", "宝田もなみ", "七ツ森りり", "大槻ひびき", "八掛うみ", "水卜さくら", "椎名ゆな", "楓ふうあ", "四宮ありす", "葵いぶき", "川上ゆう（森野雫）", "円井萌華", "青空ひかり", "水原みその", "姫咲はな", "結城りの", "miru", "春菜はな", "田中ねね", "渚みつき", "つばさ舞", "綾瀬こころ", "小早川怜子", "夏目響", "浜崎真緒", "八蜜凛", "涼森れむ", "西宮ゆめ", "小島みなみ", "凪ひかる", "北野未奈", "七沢みあ", "今井夏帆", "香水じゅん", "時田亜美", "宮下玲奈", "美園和花", "横宮七海", "星宮一花", "庵ひめか", "斎藤あみり", "小野夕子", "未歩なな");
        for (String name : names) {
            final List<String> list = Arrays.asList(
                    "d:\\20160520", "d:\\20161114", "d:\\20170531", "d:\\20170709", "d:\\20170819", "d:\\20170820", "d:\\20170902", "d:\\20171014", "d:\\20171112", "d:\\20180318", "d:\\2019999",
                    "e:\\20180727", "e:\\20181014", "e:\\20190731", "e:\\20190922", "e:\\20190924", "e:\\20191222", "e:\\20200101", "e:\\20200912", "e:\\20210704", "e:\\20210705", "e:\\20210726", "e:\\20211203", "e:\\20211204", "e:\\20211205", "e:\\20211210", "e:\\20220130", "e:\\20220216", "e:\\20220220", "e:\\20220221", "e:\\20220222", "e:\\20220223", "e:\\20220505", "e:\\20220705", "e:\\20220805", "e:\\20220811", "e:\\20220812", "e:\\20220813", "e:\\20220814", "e:\\20220815", "e:\\20220816", "e:\\20221125", "e:\\20230305", "e:\\20230312", "e:\\20230325", "e:\\20230329", "e:\\20230330", "e:\\20230504", "e:\\20230520", "e:\\20230520_batch", "e:\\20230526_batch", "e:\\20230709", "e:\\20230723", "e:\\20230813", "e:\\20230814", "e:\\20230815", "E:\\m3u8down", "E:\\20230520_batch", "E:\\20230526_batch",
                    "f:\\20170725", "f:\\20170805", "f:\\20170819", "f:\\20171112", "f:\\20180127", "f:\\20180203", "f:\\20180602", "f:\\20201102", "f:\\20201104", "f:\\20201108", "f:\\20201114", "f:\\20210630", "f:\\20210703", "f:\\20210814", "f:\\20210904", "f:\\20220203", "f:\\20221110", "f:\\20230312", "f:\\20230806", "f:\\20231001", "f:\\20231002", "f:\\20231003", "f:\\20231004", "f:\\20231016", "f:\\20231017", "f:\\223101401",
                    "g:\\20210703", "g:\\vedio", "g:\\202230703", "h:\\media", "I:\\setup\\m3u8\\hitomi_downloader_GUI\\hitomi_downloaded_torrent", "F:\\I盘文件",
                    "H:\\video", "F:\\H盘文件"
            );
            final List<Path> paths = list.stream().map(x -> Paths.get(x)).collect(Collectors.toList());
            Predicate<Path> pathPredicate = x -> x.toFile().getName().indexOf(name) != -1 && x.toFile().getName().endsWith(".mp4");
            final AllScan allScan = new AllScan(pathPredicate, paths);
            allScan.start();
            copyFile(allScan, name);
        }

    }

    public static void main3(String[] args) throws IOException {
        copyFiles();
    }

    public static void main(String[] args) throws IOException {
        final List<String> list = Arrays.asList(
                "d:\\20160520", "d:\\20161114", "d:\\20170531", "d:\\20170709", "d:\\20170819", "d:\\20170820", "d:\\20170902", "d:\\20171014", "d:\\20171112", "d:\\20180318", "d:\\2019999",
                "e:\\20180727", "e:\\20181014", "e:\\20190731", "e:\\20190922", "e:\\20190924", "e:\\20191222", "e:\\20200101", "e:\\20200912", "e:\\20210704", "e:\\20210705", "e:\\20210726", "e:\\20211203", "e:\\20211204", "e:\\20211205", "e:\\20211210", "e:\\20220130", "e:\\20220216", "e:\\20220220", "e:\\20220221", "e:\\20220222", "e:\\20220223", "e:\\20220505", "e:\\20220705", "e:\\20220805", "e:\\20220811", "e:\\20220812", "e:\\20220813", "e:\\20220814", "e:\\20220815", "e:\\20220816", "e:\\20221125", "e:\\20230305", "e:\\20230312", "e:\\20230325", "e:\\20230329", "e:\\20230330", "e:\\20230504", "e:\\20230520", "e:\\20230520_batch", "e:\\20230526_batch", "e:\\20230709", "e:\\20230723", "e:\\20230813", "e:\\20230814", "e:\\20230815", "E:\\m3u8down", "E:\\20230520_batch", "E:\\20230526_batch",
                "f:\\20170725", "f:\\20170805", "f:\\20170819", "f:\\20171112", "f:\\20180127", "f:\\20180203", "f:\\20180602", "f:\\20201102", "f:\\20201104", "f:\\20201108", "f:\\20201114", "f:\\20210630", "f:\\20210703", "f:\\20210814", "f:\\20210904", "f:\\20220203", "f:\\20221110", "f:\\20230312", "f:\\20230806", "f:\\20231001", "f:\\20231002", "f:\\20231003", "f:\\20231004", "f:\\20231016", "f:\\20231017", "f:\\223101401",
                "g:\\20210703", "g:\\vedio", "g:\\202230703", "h:\\media", "I:\\setup\\m3u8\\hitomi_downloader_GUI\\hitomi_downloaded_torrent", "F:\\I盘文件", "F:\\H盘文件",
                "H:\\video", "E:\\download\\20210404", "D:\\F盘文件", "D:\\E盘文件", "D:\\FavoriteVideo\\20180415", "D:\\makelove", "E:\\video", ""
        );
//        final List<String> list = Arrays.asList("F:\\20231001");
        final List<Path> paths = list.stream().map(x -> Paths.get(x)).collect(Collectors.toList());
        final List<String> fileEx = Arrays.asList(".mkv", ".mp4");
//        final List<String> fileEx = Arrays.asList(".mkv", ".mp4");
        Predicate<Path> pathPredicate1 = x -> {
            return fileEx.stream().anyMatch(f -> x.toAbsolutePath().toFile().getName().toString().endsWith(f));
        };
        Predicate<Path> pathPredicate2 = x -> {
            return fileEx.stream().allMatch(f -> x.toAbsolutePath().toFile().getName().toString().endsWith(f));
        };
        //Predicate<Path> pathPredicate = x -> x.toAbsolutePath().toString().indexOf("相泽") != -1;
        //Predicate<Path> pathPredicate = x -> x.toAbsolutePath().toString().indexOf("传媒") != -1;
        Predicate<Path> pathPredicate = x -> x.toAbsolutePath().toString().endsWith(".mp4");
        //Predicate<Path> pathPredicate = x -> x.toFile().getName().indexOf("紗倉まな") != -1 && x.toFile().getName().endsWith(".mp4");
        final AllScan allScan = new AllScan(pathPredicate, paths);
        allScan.start();
        System.out.println("===============================================================");
        System.out.println("allScan.getTotal() = " + allScan.getTotal());
        final List<Path> list1 = allScan.getList();
        final HashMap<String, ArrayList<Path>> summary = summary(list1);
        System.out.println("===============================================================");
        final List<Path> notOnlyOne = summary.values().stream().filter(x -> x.size() > 1).flatMap(x -> x.stream()).collect(Collectors.toList());
        final List<Path> allFile = summary.values().stream().flatMap(x -> x.stream()).collect(Collectors.toList());
        summary.forEach((k, v) -> {
            if (v.size() > 1) {
                System.out.println(k + "\t" + v.size());
                v.stream().sorted(Comparator.naturalOrder()).forEach(x -> System.out.println("\t" + x.toFile().getName() + "\t" + x));
            }
        });

        System.out.println("=============================================================== 没有重复文件");
        if (notOnlyOne.size() <= 0) {
            allFile.forEach(x -> {
                System.out.println(x.toFile().getName() + "\t" + x);
            });
        }
    }

    public static void main1(String[] args) throws Exception {
        Path path = Paths.get("G:\\vedio");
        //Predicate<Path> pathPredicate = x -> x.toAbsolutePath().toString().endsWith(".mp4");
        Predicate<Path> pathPredicate = x -> x.toAbsolutePath().toFile().getName().indexOf("相泽") != -1;
        final List<String> fileEx = Arrays.asList(".mkv", ".mp4");
//        Predicate<Path> pathPredicate1 = x -> {
//            return fileEx.stream().anyMatch(f -> x.endsWith(f));
//        };
        final List<ScanFilter> scanFilters = new ArrayList<>();
        final CountDownLatch downLatch = new CountDownLatch(1);
        ScanFilter scan = new ScanFilter(path, pathPredicate, downLatch);
        scanFilters.add(scan);
        scanFilters.forEach(x -> {
            x.start();
        });
        downLatch.await();
        System.out.println("end");
        System.out.println("scan.getFiles().size() = " + scan.getFiles().size());
//        Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
//            @Override
//            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
//                final String filePath = file.toAbsolutePath().toString();
//                if (filePath.endsWith(".mp4")) {
//                    System.out.println("filePath = " + filePath);
//                    return FileVisitResult.CONTINUE;
//                }
//                return super.visitFile(file, attrs);
//            }
//        });
    }
}
